// var o = cc.Class({
//     hex_md5: function (e) {
//         return this.binl2hex(this.core_md5(this.str2binl(e), 8 * e.length));
//     },
//     b64_md5: function (e) {
//         return this.binl2b64(this.core_md5(this.str2binl(e), 8 * e.length));
//     },
//     str_md5: function (e) {
//         return this.binl2str(this.core_md5(this.str2binl(e), 8 * e.length));
//     },
//     hex_hmac_md5: function (e, t) {
//         return this.binl2hex(this.core_hmac_md5(e, t));
//     },
//     b64_hmac_md5: function (e, t) {
//         return this.binl2b64(this.core_hmac_md5(e, t));
//     },
//     str_hmac_md5: function (e, t) {
//         return this.binl2str(this.core_hmac_md5(e, t));
//     },
//     md5_vm_test: function () {
//         return "900150983cd24fb0d6963f7d28e17f72" == this.hex_md5("abc");
//     },
//     core_md5: function (e, t) {
//         e[t >> 5] |= 128 << t % 32;
//         e[14 + (((t + 64) >>> 9) << 4)] = t;
//         var o = 1732584193;
//         var i = -271733879;
//         var n = -1732584194;
//         var a = 271733878;
//         for (var s = 0; s < e.length; s += 16) {
//             var r = o;
//             var c = i;
//             var l = n;
//             var d = a;
//             o = this.md5_ff(o, i, n, a, e[s + 0], 7, -680876936);
//             a = this.md5_ff(a, o, i, n, e[s + 1], 12, -389564586);
//             n = this.md5_ff(n, a, o, i, e[s + 2], 17, 606105819);
//             i = this.md5_ff(i, n, a, o, e[s + 3], 22, -1044525330);
//             o = this.md5_ff(o, i, n, a, e[s + 4], 7, -176418897);
//             a = this.md5_ff(a, o, i, n, e[s + 5], 12, 1200080426);
//             n = this.md5_ff(n, a, o, i, e[s + 6], 17, -1473231341);
//             i = this.md5_ff(i, n, a, o, e[s + 7], 22, -45705983);
//             o = this.md5_ff(o, i, n, a, e[s + 8], 7, 1770035416);
//             a = this.md5_ff(a, o, i, n, e[s + 9], 12, -1958414417);
//             n = this.md5_ff(n, a, o, i, e[s + 10], 17, -42063);
//             i = this.md5_ff(i, n, a, o, e[s + 11], 22, -1990404162);
//             o = this.md5_ff(o, i, n, a, e[s + 12], 7, 1804603682);
//             a = this.md5_ff(a, o, i, n, e[s + 13], 12, -40341101);
//             n = this.md5_ff(n, a, o, i, e[s + 14], 17, -1502002290);
//             i = this.md5_ff(i, n, a, o, e[s + 15], 22, 1236535329);
//             o = this.md5_gg(o, i, n, a, e[s + 1], 5, -165796510);
//             a = this.md5_gg(a, o, i, n, e[s + 6], 9, -1069501632);
//             n = this.md5_gg(n, a, o, i, e[s + 11], 14, 643717713);
//             i = this.md5_gg(i, n, a, o, e[s + 0], 20, -373897302);
//             o = this.md5_gg(o, i, n, a, e[s + 5], 5, -701558691);
//             a = this.md5_gg(a, o, i, n, e[s + 10], 9, 38016083);
//             n = this.md5_gg(n, a, o, i, e[s + 15], 14, -660478335);
//             i = this.md5_gg(i, n, a, o, e[s + 4], 20, -405537848);
//             o = this.md5_gg(o, i, n, a, e[s + 9], 5, 568446438);
//             a = this.md5_gg(a, o, i, n, e[s + 14], 9, -1019803690);
//             n = this.md5_gg(n, a, o, i, e[s + 3], 14, -187363961);
//             i = this.md5_gg(i, n, a, o, e[s + 8], 20, 1163531501);
//             o = this.md5_gg(o, i, n, a, e[s + 13], 5, -1444681467);
//             a = this.md5_gg(a, o, i, n, e[s + 2], 9, -51403784);
//             n = this.md5_gg(n, a, o, i, e[s + 7], 14, 1735328473);
//             i = this.md5_gg(i, n, a, o, e[s + 12], 20, -1926607734);
//             o = this.md5_hh(o, i, n, a, e[s + 5], 4, -378558);
//             a = this.md5_hh(a, o, i, n, e[s + 8], 11, -2022574463);
//             n = this.md5_hh(n, a, o, i, e[s + 11], 16, 1839030562);
//             i = this.md5_hh(i, n, a, o, e[s + 14], 23, -35309556);
//             o = this.md5_hh(o, i, n, a, e[s + 1], 4, -1530992060);
//             a = this.md5_hh(a, o, i, n, e[s + 4], 11, 1272893353);
//             n = this.md5_hh(n, a, o, i, e[s + 7], 16, -155497632);
//             i = this.md5_hh(i, n, a, o, e[s + 10], 23, -1094730640);
//             o = this.md5_hh(o, i, n, a, e[s + 13], 4, 681279174);
//             a = this.md5_hh(a, o, i, n, e[s + 0], 11, -358537222);
//             n = this.md5_hh(n, a, o, i, e[s + 3], 16, -722521979);
//             i = this.md5_hh(i, n, a, o, e[s + 6], 23, 76029189);
//             o = this.md5_hh(o, i, n, a, e[s + 9], 4, -640364487);
//             a = this.md5_hh(a, o, i, n, e[s + 12], 11, -421815835);
//             n = this.md5_hh(n, a, o, i, e[s + 15], 16, 530742520);
//             i = this.md5_hh(i, n, a, o, e[s + 2], 23, -995338651);
//             o = this.md5_ii(o, i, n, a, e[s + 0], 6, -198630844);
//             a = this.md5_ii(a, o, i, n, e[s + 7], 10, 1126891415);
//             n = this.md5_ii(n, a, o, i, e[s + 14], 15, -1416354905);
//             i = this.md5_ii(i, n, a, o, e[s + 5], 21, -57434055);
//             o = this.md5_ii(o, i, n, a, e[s + 12], 6, 1700485571);
//             a = this.md5_ii(a, o, i, n, e[s + 3], 10, -1894986606);
//             n = this.md5_ii(n, a, o, i, e[s + 10], 15, -1051523);
//             i = this.md5_ii(i, n, a, o, e[s + 1], 21, -2054922799);
//             o = this.md5_ii(o, i, n, a, e[s + 8], 6, 1873313359);
//             a = this.md5_ii(a, o, i, n, e[s + 15], 10, -30611744);
//             n = this.md5_ii(n, a, o, i, e[s + 6], 15, -1560198380);
//             i = this.md5_ii(i, n, a, o, e[s + 13], 21, 1309151649);
//             o = this.md5_ii(o, i, n, a, e[s + 4], 6, -145523070);
//             a = this.md5_ii(a, o, i, n, e[s + 11], 10, -1120210379);
//             n = this.md5_ii(n, a, o, i, e[s + 2], 15, 718787259);
//             i = this.md5_ii(i, n, a, o, e[s + 9], 21, -343485551);
//             o = this.safe_add(o, r);
//             i = this.safe_add(i, c);
//             n = this.safe_add(n, l);
//             a = this.safe_add(a, d);
//         }
//         return Array(o, i, n, a);
//     },
//     md5_cmn: function (e, t, o, i, n, a) {
//         return this.safe_add(this.bit_rol(this.safe_add(this.safe_add(t, e), this.safe_add(i, a)), n), o);
//     },
//     md5_ff: function (e, t, o, i, n, a, s) {
//         return this.md5_cmn((t & o) | (~t & i), e, t, n, a, s);
//     },
//     md5_gg: function (e, t, o, i, n, a, s) {
//         return this.md5_cmn((t & i) | (o & ~i), e, t, n, a, s);
//     },
//     md5_hh: function (e, t, o, i, n, a, s) {
//         return this.md5_cmn(t ^ o ^ i, e, t, n, a, s);
//     },
//     md5_ii: function (e, t, o, i, n, a, s) {
//         return this.md5_cmn(o ^ (t | ~i), e, t, n, a, s);
//     },
//     core_hmac_md5: function (e, t) {
//         var o = this.str2binl(e);
//         if (o.length > 16) {
//             o = this.core_md5(o, 8 * e.length);
//         }
//         var i = Array(16);
//         var n = Array(16);
//         for (var a = 0; a < 16; a++) {
//             i[a] = 909522486 ^ o[a];
//             n[a] = 1549556828 ^ o[a];
//         }
//         var s = this.core_md5(i.concat(this.str2binl(t)), 512 + 8 * t.length);
//         return this.core_md5(n.concat(s), 640);
//     },
//     safe_add: function (e, t) {
//         var o = (65535 & e) + (65535 & t);
//         return (((e >> 16) + (t >> 16) + (o >> 16)) << 16) | (65535 & o);
//     },
//     bit_rol: function (e, t) {
//         return (e << t) | (e >>> (32 - t));
//     },
//     str2binl: function (e) {
//         var t = Array();
//         for (var o = 0; o < 8 * e.length; o += 8) {
//             t[o >> 5] |= (255 & e.charCodeAt(o / 8)) << o % 32;
//         }
//         return t;
//     },
//     binl2str: function (e) {
//         var t = "";
//         for (var o = 0; o < 32 * e.length; o += 8) {
//             t += String.fromCharCode((e[o >> 5] >>> o % 32) & 255);
//         }
//         return t;
//     },
//     binl2hex: function (e) {
//         var t = "";
//         for (var o = 0; o < 4 * e.length; o++) {
//             t +=
//                 "0123456789abcdef".charAt((e[o >> 2] >> ((o % 4) * 8 + 4)) & 15) +
//                 "0123456789abcdef".charAt((e[o >> 2] >> ((o % 4) * 8)) & 15);
//         }
//         return t;
//     },
//     binl2b64: function (e) {
//         var t = "";
//         for (var o = 0; o < 4 * e.length; o += 3) {
//             var i =
//                 (((e[o >> 2] >> ((o % 4) * 8)) & 255) << 16) |
//                 (((e[(o + 1) >> 2] >> (((o + 1) % 4) * 8)) & 255) << 8) |
//                 ((e[(o + 2) >> 2] >> (((o + 2) % 4) * 8)) & 255);
//             for (var n = 0; n < 4; n++) {
//                 8 * o + 6 * n > 32 * e.length
//                     ? (t += "")
//                     : (t += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(
//                           (i >> (6 * (3 - n))) & 63
//                       ));
//             }
//         }
//         return t;
//     }
// });
// module.exports = o;


/** 
 * MD5加密相关功能类
 */
var MD5Helper = cc.Class({
    /**
     * 对输入字符串进行MD5加密，返回十六进制字符串
     * @param {string} input - 输入字符串
     * @returns {string} - 十六进制MD5结果
     */
    hex_md5: function (input) {
        const binl = this.str2binl(input);
        const core = this.core_md5(binl, 8 * input.length);
        return this.binl2hex(core);
    },

    /**
     * 对输入字符串进行MD5加密，返回Base64字符串
     * @param {string} input - 输入字符串
     * @returns {string} - Base64 MD5结果
     */
    b64_md5: function (input) {
        const binl = this.str2binl(input);
        const core = this.core_md5(binl, 8 * input.length);
        return this.binl2b64(core);
    },

    /**
     * 对输入字符串进行MD5加密，返回字符串
     * @param {string} input - 输入字符串
     * @returns {string} - 字符串MD5结果
     */
    str_md5: function (input) {
        const binl = this.str2binl(input);
        const core = this.core_md5(binl, 8 * input.length);
        return this.binl2str(core);
    },

    /**
     * 对输入字符串进行HMAC MD5加密，返回十六进制字符串
     * @param {string} input - 输入字符串
     * @param {string} key - 密钥
     * @returns {string} - 十六进制HMAC MD5结果
     */
    hex_hmac_md5: function (input, key) {
        return this.binl2hex(this.core_hmac_md5(input, key));
    },

    /**
     * 对输入字符串进行HMAC MD5加密，返回Base64字符串
     * @param {string} input - 输入字符串
     * @param {string} key - 密钥
     * @returns {string} - Base64 HMAC MD5结果
     */
    b64_hmac_md5: function (input, key) {
        return this.binl2b64(this.core_hmac_md5(input, key));
    },

    /**
     * 对输入字符串进行HMAC MD5加密，返回字符串
     * @param {string} input - 输入字符串
     * @param {string} key - 密钥
     * @returns {string} - 字符串HMAC MD5结果
     */
    str_hmac_md5: function (input, key) {
        return this.binl2str(this.core_hmac_md5(input, key));
    },

    /**
     * MD5测试函数
     * @returns {boolean} - 是否通过测试
     */
    md5_vm_test: function () {
        return "900150983cd24fb0d6963f7d28e17f72" === this.hex_md5("abc");
    },

    /**
     * MD5核心计算函数
     * @param {Array} binArray - 二进制数组
     * @param {number} bitLength - 位长度
     * @returns {Array} - MD5结果
     */
    core_md5: function (binArray, bitLength) {
        binArray[bitLength >> 5] |= 128 << bitLength % 32;
        binArray[14 + (((bitLength + 64) >>> 9) << 4)] = bitLength;
        let a = 1732584193, b = -271733879, c = -1732584194, d = 271733878;
        for (let i = 0; i < binArray.length; i += 16) {
            let [olda, oldb, oldc, oldd] = [a, b, c, d];

            a = this.md5_ff(a, b, c, d, binArray[i + 0], 7, -680876936);
            d = this.md5_ff(d, a, b, c, binArray[i + 1], 12, -389564586);
            c = this.md5_ff(c, d, a, b, binArray[i + 2], 17, 606105819);
            b = this.md5_ff(b, c, d, a, binArray[i + 3], 22, -1044525330);
            a = this.md5_ff(a, b, c, d, binArray[i + 4], 7, -176418897);
            d = this.md5_ff(d, a, b, c, binArray[i + 5], 12, 1200080426);
            c = this.md5_ff(c, d, a, b, binArray[i + 6], 17, -1473231341);
            b = this.md5_ff(b, c, d, a, binArray[i + 7], 22, -45705983);
            a = this.md5_ff(a, b, c, d, binArray[i + 8], 7, 1770035416);
            d = this.md5_ff(d, a, b, c, binArray[i + 9], 12, -1958414417);
            c = this.md5_ff(c, d, a, b, binArray[i + 10], 17, -42063);
            b = this.md5_ff(b, c, d, a, binArray[i + 11], 22, -1990404162);
            a = this.md5_ff(a, b, c, d, binArray[i + 12], 7, 1804603682);
            d = this.md5_ff(d, a, b, c, binArray[i + 13], 12, -40341101);
            c = this.md5_ff(c, d, a, b, binArray[i + 14], 17, -1502002290);
            b = this.md5_ff(b, c, d, a, binArray[i + 15], 22, 1236535329);

            a = this.md5_gg(a, b, c, d, binArray[i + 1], 5, -165796510);
            d = this.md5_gg(d, a, b, c, binArray[i + 6], 9, -1069501632);
            c = this.md5_gg(c, d, a, b, binArray[i + 11], 14, 643717713);
            b = this.md5_gg(b, c, d, a, binArray[i + 0], 20, -373897302);
            a = this.md5_gg(a, b, c, d, binArray[i + 5], 5, -701558691);
            d = this.md5_gg(d, a, b, c, binArray[i + 10], 9, 38016083);
            c = this.md5_gg(c, d, a, b, binArray[i + 15], 14, -660478335);
            b = this.md5_gg(b, c, d, a, binArray[i + 4], 20, -405537848);
            a = this.md5_gg(a, b, c, d, binArray[i + 9], 5, 568446438);
            d = this.md5_gg(d, a, b, c, binArray[i + 14], 9, -1019803690);
            c = this.md5_gg(c, d, a, b, binArray[i + 3], 14, -187363961);
            b = this.md5_gg(b, c, d, a, binArray[i + 8], 20, 1163531501);
            a = this.md5_gg(a, b, c, d, binArray[i + 13], 5, -1444681467);
            d = this.md5_gg(d, a, b, c, binArray[i + 2], 9, -51403784);
            c = this.md5_gg(c, d, a, b, binArray[i + 7], 14, 1735328473);
            b = this.md5_gg(b, c, d, a, binArray[i + 12], 20, -1926607734);

            a = this.md5_hh(a, b, c, d, binArray[i + 5], 4, -378558);
            d = this.md5_hh(d, a, b, c, binArray[i + 8], 11, -2022574463);
            c = this.md5_hh(c, d, a, b, binArray[i + 11], 16, 1839030562);
            b = this.md5_hh(b, c, d, a, binArray[i + 14], 23, -35309556);
            a = this.md5_hh(a, b, c, d, binArray[i + 1], 4, -1530992060);
            d = this.md5_hh(d, a, b, c, binArray[i + 4], 11, 1272893353);
            c = this.md5_hh(c, d, a, b, binArray[i + 7], 16, -155497632);
            b = this.md5_hh(b, c, d, a, binArray[i + 10], 23, -1094730640);
            a = this.md5_hh(a, b, c, d, binArray[i + 13], 4, 681279174);
            d = this.md5_hh(d, a, b, c, binArray[i + 0], 11, -358537222);
            c = this.md5_hh(c, d, a, b, binArray[i + 3], 16, -722521979);
            b = this.md5_hh(b, c, d, a, binArray[i + 6], 23, 76029189);
            a = this.md5_hh(a, b, c, d, binArray[i + 9], 4, -640364487);
            d = this.md5_hh(d, a, b, c, binArray[i + 12], 11, -421815835);
            c = this.md5_hh(c, d, a, b, binArray[i + 15], 16, 530742520);
            b = this.md5_hh(b, c, d, a, binArray[i + 2], 23, -995338651);

            a = this.md5_ii(a, b, c, d, binArray[i + 0], 6, -198630844);
            d = this.md5_ii(d, a, b, c, binArray[i + 7], 10, 1126891415);
            c = this.md5_ii(c, d, a, b, binArray[i + 14], 15, -1416354905);
            b = this.md5_ii(b, c, d, a, binArray[i + 5], 21, -57434055);
            a = this.md5_ii(a, b, c, d, binArray[i + 12], 6, 1700485571);
            d = this.md5_ii(d, a, b, c, binArray[i + 3], 10, -1894986606);
            c = this.md5_ii(c, d, a, b, binArray[i + 10], 15, -1051523);
            b = this.md5_ii(b, c, d, a, binArray[i + 1], 21, -2054922799);
            a = this.md5_ii(a, b, c, d, binArray[i + 8], 6, 1873313359);
            d = this.md5_ii(d, a, b, c, binArray[i + 15], 10, -30611744);
            c = this.md5_ii(c, d, a, b, binArray[i + 6], 15, -1560198380);
            b = this.md5_ii(b, c, d, a, binArray[i + 13], 21, 1309151649);
            a = this.md5_ii(a, b, c, d, binArray[i + 4], 6, -145523070);
            d = this.md5_ii(d, a, b, c, binArray[i + 11], 10, -1120210379);
            c = this.md5_ii(c, d, a, b, binArray[i + 2], 15, 718787259);
            b = this.md5_ii(b, c, d, a, binArray[i + 9], 21, -343485551);

            a = this.safe_add(a, olda);
            b = this.safe_add(b, oldb);
            c = this.safe_add(c, oldc);
            d = this.safe_add(d, oldd);
        }
        return [a, b, c, d];
    },

    /**
     * 通用MD5函数
     * @param {number} q - 计算结果
     * @param {number} a - 变量a
     * @param {number} b - 变量b
     * @param {number} x - 变量x
     * @param {number} s - 位移
     * @param {number} t - 常量t
     * @returns {number} - 计算结果
     */
    md5_cmn: function (q, a, b, x, s, t) {
        return this.safe_add(this.bit_rol(this.safe_add(this.safe_add(a, q), this.safe_add(x, t)), s), b);
    },

    /**
     * F函数
     */
    md5_ff: function (a, b, c, d, x, s, t) {
        return this.md5_cmn((b & c) | (~b & d), a, b, x, s, t);
    },

    /**
     * G函数
     */
    md5_gg: function (a, b, c, d, x, s, t) {
        return this.md5_cmn((b & d) | (c & ~d), a, b, x, s, t);
    },

    /**
     * H函数
     */
    md5_hh: function (a, b, c, d, x, s, t) {
        return this.md5_cmn(b ^ c ^ d, a, b, x, s, t);
    },

    /**
     * I函数
     */
    md5_ii: function (a, b, c, d, x, s, t) {
        return this.md5_cmn(c ^ (b | ~d), a, b, x, s, t);
    },

    /**
     * HMAC MD5核心计算函数
     * @param {string} key - 密钥
     * @param {string} data - 数据
     * @returns {Array} - HMAC MD5结果
     */
    core_hmac_md5: function (key, data) {
        let keyBin = this.str2binl(key);
        if (keyBin.length > 16) {
            keyBin = this.core_md5(keyBin, 8 * key.length);
        }
        const ipad = Array(16), opad = Array(16);
        for (let i = 0; i < 16; i++) {
            ipad[i] = 909522486 ^ keyBin[i];
            opad[i] = 1549556828 ^ keyBin[i];
        }
        const hash = this.core_md5(ipad.concat(this.str2binl(data)), 512 + 8 * data.length);
        return this.core_md5(opad.concat(hash), 640);
    },

    /**
     * 安全加法函数，防止溢出
     * @param {number} x - 数字x
     * @param {number} y - 数字y
     * @returns {number} - 加法结果
     */
    safe_add: function (x, y) {
        const low = (65535 & x) + (65535 & y);
        const high = (x >> 16) + (y >> 16) + (low >> 16);
        return (high << 16) | (65535 & low);
    },

    /**
     * 位循环左移
     * @param {number} num - 数字
     * @param {number} cnt - 位数
     * @returns {number} - 结果
     */
    bit_rol: function (num, cnt) {
        return (num << cnt) | (num >>> (32 - cnt));
    },

    /**
     * 字符串转二进制数组
     * @param {string} str - 输入字符串
     * @returns {Array} - 二进制数组
     */
    str2binl: function (str) {
        const bin = [];
        for (let i = 0; i < str.length * 8; i += 8) {
            bin[i >> 5] |= (str.charCodeAt(i / 8) & 255) << (i % 32);
        }
        return bin;
    },

    /**
     * 二进制数组转字符串
     * @param {Array} bin - 二进制数组
     * @returns {string} - 输出字符串
     */
    binl2str: function (bin) {
        let str = "";
        for (let i = 0; i < bin.length * 32; i += 8) {
            str += String.fromCharCode((bin[i >> 5] >>> (i % 32)) & 255);
        }
        return str;
    },

    /**
     * 二进制数组转十六进制字符串
     * @param {Array} bin - 二进制数组
     * @returns {string} - 十六进制字符串
     */
    binl2hex: function (bin) {
        let hex = "";
        for (let i = 0; i < bin.length * 4; i++) {
            hex +=
                "0123456789abcdef".charAt((bin[i >> 2] >> ((i % 4) * 8 + 4)) & 15) +
                "0123456789abcdef".charAt((bin[i >> 2] >> ((i % 4) * 8)) & 15);
        }
        return hex;
    },

    /**
     * 二进制数组转Base64字符串
     * @param {Array} bin - 二进制数组
     * @returns {string} - Base64字符串
     */
    binl2b64: function (bin) {
        let base64 = "";
        const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        for (let i = 0; i < bin.length * 4; i += 3) {
            const triplet =
                (((bin[i >> 2] >> ((i % 4) * 8)) & 255) << 16) |
                (((bin[(i + 1) >> 2] >> (((i + 1) % 4) * 8)) & 255) << 8) |
                ((bin[(i + 2) >> 2] >> (((i + 2) % 4) * 8)) & 255);
            for (let j = 0; j < 4; j++) {
                base64 += 8 * i + 6 * j > bin.length * 32
                    ? ""
                    : chars.charAt((triplet >> (6 * (3 - j))) & 63);
            }
        }
        return base64;
    }
});

module.exports = MD5Helper;
